/*
根据CTCMaster.h的定义,此文件为CTC协议主控端的实现文件.
*/

#include "CTCMaster.h"

// 内部变量定义
static CTCBuffer sendBuffer;                                                                    // 发送缓冲区，用于存储待发送的数据
static CTCBuffer receiveBuffer;                                                                 // 接收缓冲区，用于存储接收到的数据
static CTC_SendDataCallback sendDataCallback                = NULL;                             // 串口发送数据回调函数
static CTC_ConnStateChangeCallback slaveStateChangeCallback = NULL;                             // 连接状态变化回调函数
static CTC_MsgSendCallback datasendresultCallback           = NULL;                             // 数据发送结果回调函数
static uint32_t sendTransactionId                           = 1;                                // 发送事务ID，从1开始，每次发送自增
static uint32_t receiveTransactionId                        = 0;                                // 接收事务ID，从0开始，用于防止重复处理
static uint16_t reconnectTimes                              = 0;                                // 重新连接次数计数器
static uint32_t totalresendMsgCount                         = 0;                                // 总重发消息数统计
static uint32_t totalReceivedBytes                          = 0;                                // 总接收字节数统计
static uint32_t totalSentBytes                              = 0;                                // 总发送字节数统计
static uint32_t totalReceivedMsgCount                       = 0;                                // 总接收正确消息数统计
static uint32_t totalSentMsgCount                           = 0;                                // 总发送正确消息数统计
static uint32_t totalReceivedErrorMsgCount                  = 0;                                // 总接收错误消息数统计
static uint32_t lastSlaveCommTime                           = 0;                                // 最后一次从设备响应的时间（毫秒）
static uint8_t masterDeviceId[16]                           = {0};                              // 主控设备ID，用于标识当前设备
static uint8_t slaveDeviceId[16]                            = {0};                              // 从设备ID，用于标识连接的从设备
static uint64_t mastertimer                                 = 0;                                // 主控定时器（毫秒）
static uint64_t nextsenddatatime                            = 0;                                // 下次发送时间（毫秒）
static uint64_t nextrevicetime                              = 0;                                // 下次接收时间（毫秒）
static uint64_t receiveTimeout                              = 0;                                // 接收超时时间（毫秒）0表示不启用
static uint8_t isbufferfull                                 = 0;                                // 主控发送缓冲区满标志
static uint16_t lastslavestate                              = CTC_STATE_UNKNOWN;                // 上次连接设备的状态
static uint8_t slaveconsumable                              = 1;                                // Slave设备是否可消费1=不可消费,0=可消费
static uint8_t masterstate                                  = 0;                                // 当前连接设备的状态,0=正常可用,1=等待配网,2=连接门店服务异常,3=网络无法连接,4=正在联网
static uint64_t nextKeepConnectTime                         = 0;                                // 下次保持连接时间（毫秒）
static uint16_t slaveCTCversion                             = 0;                                // 连接设备的CTC协议版本
static uint8_t checkOfflinetimer                            = 0;                                // 掉线检查定时器
static CTC_ClientConnState connState                        = CTC_CLIENT_CONNSTATE_CONNECTTING; // 尝试连接状态

// 抄表回调结果指针
static CTC_Master_ReadMeterCallback readMeterCallback = NULL;
/// 投币结果回调函数指针
static CTC_Master_CoinInCallback coinInCallback = NULL;
// 查询单价结果回调函数指针
static CTC_Master_QueryCoinPriceCallback queryCoinPriceCallback = NULL;
// 氛围事件回调函数指针
static CTC_Master_AtmosphereEventCallback atmosphereEventCallback = NULL;
// 游戏奖励回调函数指针
static CTC_Master_GameRewardEventCallback rewardEventCallback = NULL;
// 实物奖励回调函数指针
static CTC_Master_PhysicalRewardCallback physicalRewardCallback = NULL;

/// @brief 初始化CTC主控端
/// @note 需要在程序初始化时调用,会初始化发送和接收缓冲区,并设置初始状态为尝试连接状态
/// @note 需要在主循环中每隔1ms调用CTC_Master_Loop1ms()函数
/// @param  无
void CTC_Master_Init(void)
{
    DEBUG_INFO("CTC Master Init\r\n");
    CTCBuffer_Init(&sendBuffer);
    CTCBuffer_Init(&receiveBuffer);
    reconnectTimes             = 0;
    sendTransactionId          = 1;
    receiveTransactionId       = 0;
    totalresendMsgCount        = 0;
    totalReceivedBytes         = 0;
    totalSentBytes             = 0;
    totalReceivedMsgCount      = 0;
    totalSentMsgCount          = 0;
    totalReceivedErrorMsgCount = 0;
    lastSlaveCommTime          = 0;
    mastertimer                = 0;
    nextsenddatatime           = 0;
    nextrevicetime             = 0;
    nextKeepConnectTime        = 0;
    connState                  = CTC_CLIENT_CONNSTATE_CONNECTTING;
    isbufferfull               = 0;
    lastslavestate             = CTC_STATE_UNKNOWN;
    masterstate                = 0;
    slaveconsumable            = 1;
    slaveCTCversion            = 0;
    receiveTimeout             = 0;
    checkOfflinetimer          = 0;
    memset(masterDeviceId, 0, sizeof(masterDeviceId));
    memset(slaveDeviceId, 0, sizeof(slaveDeviceId));
}

/// @brief 获取下一个发送事务ID
uint32_t CTC_Master_GetNextSendTransactionId(void)
{
    sendTransactionId++;
    if (sendTransactionId == 0) sendTransactionId = 1; // 避免为0
    return sendTransactionId;
}

/// @brief 通用发送消息函数
/// @param cmdid 命令ID
/// @param msg 指向消息结构体指针
/// @param msglen 消息长度
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendMsgCommand(uint16_t cmdid, const void *msg, uint8_t msglen)
{
    if (msg == NULL && msglen > 0) {
        DEBUG_WARN("CTC Master SendMsg Command :%d Msg Is NULL\r\n", cmdid);
        return 0;
    }
    //断联或者未连接状态只允许发送握手指令
    if (connState != CTC_CLIENT_CONNSTATE_CONNECTED) {
        if (cmdid != CTC_CMD_HANDSHAKE) {
            DEBUG_WARN("CTC Master SendMsg Command :%d Connection State:%d,Can't Send Msg\r\n", cmdid, connState);
            return 0;
        }
    }
    uint32_t nexttransactionid = CTC_Master_GetNextSendTransactionId();
    CTCBuffer_Lock(&sendBuffer);
    CTC_BufferResult res = CTCBuffer_WriteMsgToSendBuffer(&sendBuffer, CTC_DEFAULT_PORTID, cmdid, nexttransactionid, (uint8_t *)msg, msglen);
    CTCBuffer_Unlock(&sendBuffer);
    if (res != CTC_BUFFER_SUCCESS) {
        DEBUG_WARN("CTC Master SendMsg Command :%d Write To Send Buffer Failed:%d\r\n", cmdid, res);
        return 0;
    }
    nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME;
    // DEBUG_INFO("CTC Master SendMsg Command :%d TransactionID:%d\r\n", cmdid, nexttransactionid);
    return nexttransactionid;
}

/// @brief 发送握手指令
void CTC_Master_SendHandshake(void)
{
    DEBUG_INFO("CTC Master Send Handshake\r\n");
    uint8_t data[CTC_CMDLEN_HANDSHAKE];
    CTCBuffer_Uint32ToBytes(CTC_MASTER_PRODUCTID, &data[0]); // 产品ID
    memcpy(&data[4], masterDeviceId, 16);                    // 设备ID
    CTCBuffer_Uint16ToBytes(CTC_MASTER_VERSION, &data[20]);  // 最大CTC版本
    CTC_Master_SendMsgCommand(CTC_CMD_HANDSHAKE, data, CTC_CMDLEN_HANDSHAKE);
}

/// @brief 发送心跳指令
void CTC_Master_SendHeartbeat(void)
{
    DEBUG_INFO("CTC Master Send Heartbeat,State:%d\r\n", masterstate);
    CTC_Master_SendMsgCommand(CTC_CMD_HEARTBEAT, &masterstate, CTC_CMDLEN_HEARTBEAT);
}

/// @brief 发送其他数据后重置心跳时间
void CTC_Master_ResetKeepConnectTime(void)
{
    nextKeepConnectTime = mastertimer + CTC_HEARTBEAT_TIME;
}

/// @brief 检查连接状态并发送握手或心跳
void CTC_Master_CheckConnectionStatus(void)
{
    if (checkOfflinetimer < mastertimer) {
        // 检查最后一次从设备响应时间,如果超过30秒没有响应则认为断线
        if (connState == CTC_CLIENT_CONNSTATE_CONNECTED && (mastertimer - lastSlaveCommTime) > CTC_OFFLINE_TIME) {
            // 断线,需要重新连接
            DEBUG_WARN("CTC Master Connection Lost,Try Reconnect\r\n");
            connState = CTC_CLIENT_CONNSTATE_CONNECTTING; // 断线重连或尝试连接状态
            // 回调连接状态变化
            if (slaveStateChangeCallback) {
                slaveStateChangeCallback(CTC_CLIENT_CONNSTATE_CONNECTTING, CTC_CLIENT_CONNSTATE_CONNECTED); // 回调状态变化
            }
            nextKeepConnectTime = mastertimer + CTC_HANDSHAKE_RETRY_TIME;
        }
        checkOfflinetimer = mastertimer + 1000; // 每秒检查一次
    }
    if (nextKeepConnectTime > mastertimer) {
        return; // 还不到保持连接时间
    }
    // DEBUG_INFO("CTC Master Check Connection State:%d\r\n", connState);
    //  已连接时每CTC_HEARTBEAT_TIME毫秒发送一次心跳,未连接时每CTC_HANDSHAKE_RETRY_TIME毫秒发送一次握手
    switch (connState) {
        case CTC_CLIENT_CONNSTATE_CONNECTED:
            // 已连接就发送心跳数据
            if (CTCBuffer_DataLength(&sendBuffer) == 0) {
                // 发送缓冲区为空才发送心跳
                CTC_Master_SendHeartbeat();
            }
            CTC_Master_ResetKeepConnectTime();
            break;
        case CTC_CLIENT_CONNSTATE_CONNECTTING:
        case CTC_CLIENT_CONNSTATE_OFFLINE:
            // // 判断参数是否齐全,CTC1.0不检查此参数
            // if (CTCBuffer_IsAllZero(masterDeviceId, 16)) {
            //     // 设备ID未设置
            //     DEBUG_ERROR("CTC Master DeviceID Not Set,Can Not Connect\r\n");
            //     connState           = CTC_CLIENT_CONNSTATE_OFFLINE; // 参数不足没法建立连接
            //     nextKeepConnectTime = mastertimer + CTC_HANDSHAKE_RETRY_TIME;
            //     return; // 参数不足无法连接
            // }
            // 尝试连接状态就发送握手数据
            if (CTCBuffer_DataLength(&sendBuffer) == 0) {
                // 发送缓冲区为空才发送握手
                CTC_Master_SendHandshake();
            }
            nextKeepConnectTime = mastertimer + CTC_HANDSHAKE_RETRY_TIME;
            break;
    }
}

/// @brief 马上检查连接状态,不等待心跳时间到
void CTC_Master_ForceCheckConnectionStatus(void)
{
    nextKeepConnectTime = 0;
    CTC_Master_CheckConnectionStatus();
}

/// @brief 心跳发送结果处理
CTC_MsgReSendAction CTC_Master_HandleHeartbeatSendRes(CTC_AckResult result, uint32_t transactionId)
{
    // DEBUG_INFO("-----------------------------CTC Master Heartbeat Send Result:%d\r\n", result);
    return CTC_TIMEOUT_DATAACT_MISS; // 删除此消息
}

/// @brief 握手发送结果处理
CTC_MsgReSendAction CTC_Master_HandleHandshakeSendRes(CTC_AckResult result, uint32_t transactionId)
{
    // DEBUG_INFO("-----------------------------CTC Master Handshake Send Result:%d\r\n", result);
    return CTC_TIMEOUT_DATAACT_MISS; // 删除此消息
}

/// @brief 心跳回应处理
void CTC_Master_HandleHeartbeatResponse(CTC_HeartbeatRspMsgV1 *rsp)
{
    if (lastslavestate != rsp->Status || slaveconsumable != rsp->AllowCoin) {
        // 状态变化了
        lastslavestate  = rsp->Status;
        slaveconsumable = rsp->AllowCoin;
        if (slaveconsumable > 1) slaveconsumable = 1; // 只允许0或1
        DEBUG_INFO("CTC Master Slave State: %d,Consumable:%d\r\n", lastslavestate, slaveconsumable);
        // 回调连接状态变化
        if (slaveStateChangeCallback) {
            slaveStateChangeCallback(connState, connState); // 回调状态变化
        }
    }
}

/// @brief 握手回应处理
void CTC_Master_HandleHandshakeResponse(CTC_HandshakeRspMsgV1 *rsp)
{
    memcpy(slaveDeviceId, rsp->DeviceID, 16); // 保存从设备ID
    slaveCTCversion = rsp->MaxCTCVersion;     // 保存从设备CTC协议版本
    DEBUG_INFO("CTC Master Handshake Success,Slave CTC Version:%d\r\n", slaveCTCversion);
    // 握手成功,更新状态
    if (connState != CTC_CLIENT_CONNSTATE_CONNECTED) {
        // 变化前的状态
        CTC_ClientConnState prevState = connState;
        connState                     = CTC_CLIENT_CONNSTATE_CONNECTED; // 已连接状态
        // 回调连接状态变化
        if (slaveStateChangeCallback) {
            slaveStateChangeCallback(CTC_CLIENT_CONNSTATE_CONNECTED, prevState); // 回调状态变化
        }
    }
    // 马上发送一次心跳
    CTC_Master_SendHeartbeat();
    CTC_Master_ResetKeepConnectTime(); // 重置心跳时间
}

/// @brief 处理发送缓冲区数据
void CTC_Master_SendBufferData(void)
{
    if (mastertimer < nextsenddatatime) return; // 至少间隔10ms发送一次
    uint8_t data[CTC_MAX_FRAME_LEN];            // 发送缓冲区数据
    uint8_t length = 0;                         // 消息长度
    uint8_t sendtimes;                          // 发送次数
    CTCBuffer_Lock(&sendBuffer);
    uint8_t res = CTCBuffer_ReadCommandFromSendBuffer(&sendBuffer, data, &length, &sendtimes);
    CTCBuffer_Unlock(&sendBuffer);
    if (res != CTC_BUFFER_SUCCESS) {
        if (res != CTC_BUFFER_EMPTY) {
            DEBUG_ERROR("CTC Master Read Send Buffer Error:%d\r\n", res);
        }
        nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME;
        return;
    }
    if (sendtimes > CTC_MAXRESEND_TIMES) {
        // 超过最大重发次数,询问上层应用怎么处理
        CTC_MsgReSendAction timeoutaction = CTC_TIMEOUT_DATAACT_MISS;          // 默认删除
        uint32_t transactionid            = CTCBuffer_BytesToUint32(&data[5]); // 事务ID
        uint16_t cmdid                    = CTCBuffer_BytesToUint16(&data[3]); // 命令ID
        switch (cmdid) {
            case CTC_CMD_HANDSHAKE:
                // 握手超时处理
                timeoutaction = CTC_Master_HandleHandshakeSendRes(CTC_ACK_TIMEOUT, transactionid);
                break;
            case CTC_CMD_HEARTBEAT:
                // 心跳超时处理
                timeoutaction = CTC_Master_HandleHeartbeatSendRes(CTC_ACK_TIMEOUT, transactionid);
                break;
            default:
                if (datasendresultCallback) {
                    timeoutaction = datasendresultCallback(CTC_ACK_TIMEOUT, cmdid, transactionid); // 询问上层应用是丢弃还是继续重发
                }
                break;
        }
        if (timeoutaction == CTC_TIMEOUT_DATAACT_RESEND) {
            // 保留此消息,不删除,继续重发
            DEBUG_WARN("CTC Master Message Resend Exceed Max Times,Keep It TransactionID=%d\r\n", transactionid);
            CTCBuffer_Lock(&sendBuffer);
            CTCBuffer_ResetSendTimes(&sendBuffer); // 重置发送次数
            CTCBuffer_Unlock(&sendBuffer);
        } else {
            // 删除此消息
            CTCBuffer_Lock(&sendBuffer);
            CTCBuffer_DeleteFirstCommandFromSend(&sendBuffer, cmdid, transactionid);
            CTCBuffer_Unlock(&sendBuffer);
            DEBUG_WARN("CTC Master Message Resend Exceed Max Times,Delete It CmdID=%d,TransactionID=%d\r\n", cmdid, transactionid);
            totalresendMsgCount++;
            nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME; // 发送后等待10ms再发送下一帧
            return;                                              // 删除后不发送
        }
    }
    if (sendtimes > 0) {
        // 统计重发消息数量
        totalresendMsgCount++;
        DEBUG_INFO("CTC Master Resend Message,Times=%d\r\n", sendtimes);
    }
    sendDataCallback(data, length);
    // DEBUG_INFO("CTC Master Send Data Len=%d\r\n", length);
    totalSentBytes += length;
    totalSentMsgCount++;
    nextsenddatatime = mastertimer + CTC_RESEND_TIMEOUT; // 超时重发
    CTC_Master_ResetKeepConnectTime();                   // 有数据发延迟心跳时间
}

/// @brief 立即发送ACK回应
void CTC_Master_SendACK(uint8_t portid, uint16_t cmdid, uint32_t transactionId, CTC_AckResult result)
{
    uint8_t ackframe[CTC_ACKFRAME_LEN];
    CTCBuffer_AssembleAckData(ackframe, portid, cmdid, transactionId, result);
    if (sendDataCallback) {
        sendDataCallback(ackframe, CTC_ACKFRAME_LEN);
        nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME; // 发送后等待10ms再发送下一帧
        nextrevicetime   = mastertimer + CTC_MIN_FRAME_TIME; // 发送后等待10ms再接收下一帧避免粘包
    } else {
        DEBUG_ERROR("CTC Master Send ACK Failed: No Send Callback\r\n");
    }
    CTC_Master_ResetKeepConnectTime(); // 重置心跳时间
}

/// @brief 检查发送缓冲区是否满并回应ACK
void CTC_Master_CheckSendBufferFull(void)
{
    if (mastertimer < nextsenddatatime) return; // 还不到发送时间
    if (isbufferfull) {
        // 发送缓冲区满,回应错误的ACK,表示忙,并要求对方等会再发
        CTC_Master_SendACK(CTC_DEFAULT_PORTID, 0, 0, CTC_ACK_BUSY);
        isbufferfull = 0; // 清除标志
    }
}

/// @brief 处理ACK应答的数据
void CTC_Master_HandleAckResponse(uint8_t portid, uint16_t ackcmdid, uint32_t transactionid, uint8_t result)
{
    switch (result) {
        case CTC_ACK_SUCCESS:     // 成功
        case CTC_ACK_UNSUPPORTED: // 不支持的命令
        case CTC_ACK_LENGTH_ERR:  // 长度错误
            // 删除发送缓冲区的第一条消息
            {
                uint8_t res = CTCBuffer_DeleteFirstCommandFromSend(&sendBuffer, ackcmdid, transactionid);
                if (res != CTC_BUFFER_SUCCESS) {
                    DEBUG_ERROR("CTC Master Delete First Send Command Failed:%d\r\n", res);
                    if (res == CTC_BUFFER_CMDNOTMATCH) {
                        // 回应的ACK不是当前发送的命令
                        DEBUG_ERROR("CTC Master ACK Command Not Match,CmdID=%d,TransactionID=%d\r\n", ackcmdid, transactionid);
                        return;
                    }
                }
                // 回调发送结果
                switch (ackcmdid) {
                    case CTC_CMD_HANDSHAKE:
                        DEBUG_INFO("CTC Master Send Handshake OK\r\n");
                        CTC_Master_HandleHandshakeSendRes(CTC_ACK_SUCCESS, transactionid);
                        break;
                    case CTC_CMD_HEARTBEAT:
                        DEBUG_INFO("CTC Master Send Heartbeat OK\r\n");
                        CTC_Master_HandleHeartbeatSendRes(CTC_ACK_SUCCESS, transactionid);
                        break;
                    default:
                        if (datasendresultCallback) {
                            datasendresultCallback((CTC_AckResult)result, ackcmdid, transactionid); // 回调发送结果
                        }
                        break;
                }
            }
            nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME; // 取消重发按正常节奏发送
            // DEBUG_INFO("CTC Master Received ACK Success\r\n");
            break;

        case CTC_ACK_BUSY:
            // 对方设备忙,发送缓冲区满,稍后重发
            nextsenddatatime = mastertimer + CTC_BUSYRETRY_TIME; // 等待一段时间再尝试发送
            DEBUG_INFO("CTC Master Received ACK Busy\r\n");
            break;

        case CTC_ACK_HEADER_ERR:
            // 包头错误,可能是丢包引起的
            nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME; // 发送后等待10ms再发送下一帧
            DEBUG_INFO("CTC Master Received ACK Header Error\r\n");
            break;

        case CTC_ACK_CRC_ERR:
            // 包头错误,可能是干扰引起的
            nextsenddatatime = mastertimer + CTC_MIN_FRAME_TIME; // 发送后等待10ms再发送下一帧
            DEBUG_INFO("CTC Master Received ACK CRC Error\r\n");
            break;

        default:
            // 未知ACK应答,不需要处理
            break;
    }
}

/// @brief 处理接收缓冲区数据
void CTC_Master_ReceiveBufferData(void)
{
    if (mastertimer < nextrevicetime) return; // 还不到接收时间
    uint8_t bufferres      = 0;
    uint8_t portid         = 0;
    uint16_t cmdid         = 0;
    uint32_t transactionid = 0;
    uint8_t datafield[CTC_MAX_DATA_LEN];
    uint8_t datalen = 0;
    CTCBuffer_Lock(&receiveBuffer);
    bufferres = CTCBuffer_ParseFromReceiveBuffer(&receiveBuffer, &portid, &cmdid, &transactionid, datafield, &datalen);
    CTCBuffer_Unlock(&receiveBuffer);
    if (bufferres == CTC_BUFFER_EMPTY) {
        nextrevicetime = mastertimer + CTC_MIN_FRAME_TIME; // 没有数据,每10ms检查一次
        return;                                            // 无数据
    }
    if (bufferres != CTC_BUFFER_SUCCESS) {
        if (bufferres == CTC_BUFFER_PARSE_WAITMORE) {
            // 等待更多数据
            if (receiveTimeout > 0) {
                if (mastertimer > receiveTimeout) {
                    // 超时未收到完整数据,清空缓冲区
                    DEBUG_WARN("CTC Master Receive Timeout,Clear Buffer\r\n");
                    CTCBuffer_Lock(&receiveBuffer);
                    CTCBuffer_Init(&receiveBuffer);
                    CTCBuffer_Unlock(&receiveBuffer);
                    totalReceivedErrorMsgCount++;
                    receiveTimeout = 0;
                } else {
                    nextrevicetime = mastertimer + CTC_MIN_FRAME_TIME; // 每10ms检查一次
                }
            } else {
                receiveTimeout = mastertimer + CTC_RECEIVE_TIMEOUT; // 设置超时时间
            }
            return;
        } else {
            receiveTimeout = 0; // 清除超时标志
        }

        if (bufferres == CTC_BUFFER_PARSE_HEADNOTFOUND) {
            // 包头未找到,清空缓冲区
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_HEADER_ERR);
            totalReceivedErrorMsgCount++;
            return;
        } else if (bufferres == CTC_BUFFER_PARSE_CRCERROR) {
            // CRC错误,丢弃此帧数据
            totalReceivedErrorMsgCount++;
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_CRC_ERR); // 回应错误ACK
            return;
        }
        // 其他错误
        totalReceivedErrorMsgCount++;
        DEBUG_WARN("CTC Master Receive Buffer Parse Error:%d\r\n", bufferres);
        return;
    }
    receiveTimeout = 0;                                   // 清除超时标志
    totalReceivedBytes += (datalen + CTC_FRAME_OVERHEAD); // 统计接收字节数
    totalReceivedMsgCount++;                              // 统计接收正确消息数
    lastSlaveCommTime = mastertimer;                      // 更新最后通信时间

    if (cmdid == CTC_CMD_ACK) {
        // ACK回应不检查重复事务ID
        // 收到应答指令,说明从设备已收到之前发送的消息,可以删除发送缓冲区的第一条消息,并回调发送结果
        if (datalen != 3) {
            // 数据长度错误
            DEBUG_WARN("CTC Master ACK Length Error:%d\r\n", datalen);
            totalReceivedErrorMsgCount++;
            // 有错误的时候放慢接收速度
            nextrevicetime = mastertimer + CTC_WAITTIMEONERR; // 通讯错误延时接收
            return;
        }
        CTC_Master_HandleAckResponse(portid, CTCBuffer_BytesToUint16(datafield), transactionid, datafield[2]); // 处理应答
        return;
    }

    if (receiveTransactionId == transactionid) {
        // 重复的事务ID,丢弃此帧数据,但回应ACK
        DEBUG_WARN("CTC Master Receive Buffer Duplicate TransactionID:%d\r\n", transactionid);
        // 回应ACK
        CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS);
        return;
    }
    receiveTransactionId = transactionid; // 更新已处理的事务ID
    // 处理命令
    switch (cmdid) {
        case CTC_CMD_HANDSHAKE_RSP: // 握手应答
            if (datalen != CTC_CMDLEN_HANDSHAKE_RSP) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Handshake Rsp Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            CTC_HandshakeRspMsgV1 rsphsmsg;
            rsphsmsg.ProductID = CTCBuffer_BytesToUint32(&datafield[0]);
            memcpy(rsphsmsg.DeviceID, &datafield[4], 16);
            rsphsmsg.MaxCTCVersion = CTCBuffer_BytesToUint16(&datafield[20]);
            CTC_Master_HandleHandshakeResponse(&rsphsmsg); // 处理握手应答
            break;
        case CTC_CMD_HEARTBEAT_RSP: // 心跳应答
            if (datalen != CTC_CMDLEN_HEARTBEAT_RSP) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Heartbeat Rsp Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS);
            CTC_HeartbeatRspMsgV1 rsphbmsg;
            rsphbmsg.AllowCoin = datafield[0];
            rsphbmsg.Status    = CTCBuffer_BytesToUint16(&datafield[1]);
            CTC_Master_HandleHeartbeatResponse(&rsphbmsg); // 处理心跳应答
            break;
        case CTC_CMD_METER_DATA: // 读表数据
            if (datalen != CTC_CMDLEN_METER_DATA_RSP) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Meter Data Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            if (readMeterCallback) {
                CTC_MeterDataRspMsgV1 meterDataMsg;
                for (uint8_t i = 0; i < 10; i++) {
                    meterDataMsg.Items[i].MeterType  = datafield[i * 5];
                    meterDataMsg.Items[i].MeterValue = CTCBuffer_BytesToUint32(&datafield[i * 5 + 1]);
                }
                readMeterCallback(&meterDataMsg); // 回调抄表结果
            }
            break;
        case CTC_CMD_COIN_IN_RSP: // 投币结果
            if (datalen != CTC_CMDLEN_COIN_IN_RSP) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Coin In Rsp Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            if (coinInCallback) {
                CTC_CoinInRspMsgV1 coinInRspMsg;
                coinInRspMsg.Result = datafield[0];
                memcpy(coinInRspMsg.RecordId, &datafield[1], 16);
                coinInCallback(&coinInRspMsg); // 回调投币结果
            }
            break;
        case CTC_CMD_QUERY_COIN_RSP: // 查询单价结果
            if (datalen != CTC_CMDLEN_QUERY_COIN) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Query Coin Rsp Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            if (queryCoinPriceCallback) {
                CTC_CoinPriceMsgV1 queryCoinPriceRspMsg;
                queryCoinPriceRspMsg.CoinPerGame = CTCBuffer_BytesToUint16(&datafield[0]);
                queryCoinPriceCallback(&queryCoinPriceRspMsg); // 回调查询单价结果
            }
            break;
        case CTC_CMD_ATMOSPHEREEVENT: // 氛围灯事件
            if (datalen != CTC_CMDLEN_ATMOSPHERE_EVENT) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Atmosphere Event Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            if (atmosphereEventCallback) {
                CTC_AtmosphereDataV1 atmosphereEventMsg;
                atmosphereEventMsg.EventLevel  = CTCBuffer_BytesToUint16(&datafield[0]);
                atmosphereEventMsg.RewardType  = datafield[2];
                atmosphereEventMsg.RewardCount = CTCBuffer_BytesToUint32(&datafield[3]);
                atmosphereEventCallback(&atmosphereEventMsg); // 回调氛围灯事件
            }
            break;
        case CTC_CMD_REWARD: // 游戏奖励
            if (datalen != CTC_CMDLEN_REWARD) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Game Reward Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR); // 回应错误ACK
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS); // 回应ACK
            if (rewardEventCallback) {
                CTC_RewardMsgV1 gameRewardMsg;
                gameRewardMsg.RewardType  = datafield[0];
                gameRewardMsg.RewardCount = CTCBuffer_BytesToUint32(&datafield[1]);
                rewardEventCallback(&gameRewardMsg); // 回调游戏奖励事件
            }
            break;
        case CTC_CMD_PHYSICAL_REPORT: // 实物奖励结果
            if (datalen != CTC_CMDLEN_PHYSICAL_REPORT) {
                // 数据长度错误
                DEBUG_WARN("CTC Master Physical Report Length Error:%d\r\n", datalen);
                CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_LENGTH_ERR);
                totalReceivedErrorMsgCount++;
                break;
            }
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_SUCCESS);
            if (physicalRewardCallback) {
                CTC_PhysicalReportMsgV1 physicalReportMsg;
                physicalReportMsg.PhysicalType  = datafield[0];
                physicalReportMsg.PhysicalCount = CTCBuffer_BytesToUint32(&datafield[1]);
                physicalRewardCallback(&physicalReportMsg);
            }
            break;
        default:
            // 不支持的指令
            CTC_Master_SendACK(portid, cmdid, transactionid, CTC_ACK_UNSUPPORTED); // 回应不支持ACK
            DEBUG_WARN("CTC Master Received Unsupported Command ID:%d\r\n", cmdid);
            totalReceivedErrorMsgCount++;
            break;
    }
    if (connState == CTC_CLIENT_CONNSTATE_CONNECTTING || connState == CTC_CLIENT_CONNSTATE_OFFLINE) {
        // 刚连接上就收到数据,说明连接成功
        // 马上检查连接状态
        CTC_Master_ForceCheckConnectionStatus();
    }
}

/// @brief 主循环处理函数
/// @note 根据当前状态进行数据处理,发现发送缓冲区有数据就发送数据,发现接收缓冲区有数据就处理数据
/// @note 需要在主循环中每1ms调用一次
/// @param  无
void CTC_Master_Loop1ms(void)
{
    mastertimer++;
    // 检查发送缓冲区是否满并回应ACK
    CTC_Master_CheckSendBufferFull();
    // 保持连接状态
    CTC_Master_CheckConnectionStatus();
    // 处理接收缓冲区
    CTC_Master_ReceiveBufferData();
    // 处理发送缓冲区
    CTC_Master_SendBufferData();
}

/// @brief 设置Slave设备状态变化回调函数
/// @param callback 回调函数指针
void CTC_Master_SetSlaveStateChangeCallback(CTC_ConnStateChangeCallback callback)
{
    slaveStateChangeCallback = callback;
}

/// @brief 串口收到数据需要推送到此函数
/// @note 需要在串口接收中断中调用
/// @param data 接收到的数据指针
/// @param len 数据长度
void CTC_Master_ReceiveData(uint8_t *data, uint16_t len)
{
    CTCBuffer_Lock(&receiveBuffer);
    totalReceivedBytes += len; // 统计接收字节数
    if (CTCBuffer_Write(&receiveBuffer, data, len) != CTC_BUFFER_SUCCESS) {
        isbufferfull = 1; // 标记发送缓冲区满
    }
    CTCBuffer_Unlock(&receiveBuffer);
    nextrevicetime = mastertimer + CTC_MIN_FRAME_TIME; // 接收后等待10ms再处理,避免不完整
}

/// @brief 获取离线时间(秒)
/// @return 返回当前离线时间,单位秒,如果在线返回0
uint32_t CTC_Master_GetOfflineTime(void)
{
    return (mastertimer - lastSlaveCommTime) / 1000;
}

/// @brief 设置当前状态
/// @param devicestate 当前设备状态,0=正常可用,1=等待配网,2=连接门店服务异常,3=网络无法连接,4=正在联网
void CTC_Master_SetMasterState(uint8_t state)
{
    if (state != masterstate) {
        // 状态变化了,发心跳进行通知
        masterstate = state;
        if (connState == CTC_CLIENT_CONNSTATE_CONNECTED) {
            CTC_Master_SendHeartbeat();
        }
    }
}

/// @brief 获取Slave端设备状态
/// @return 返回Slave端设备状态,如果未握手或未连接则返回0
uint8_t CTC_Master_GetSlaveDeviceState(void)
{
    return lastslavestate;
}

/// @brief 设置发送数据回调函数
/// @param callback 回调函数指针
void CTC_Master_SetSendDataCallback(CTC_SendDataCallback callback)
{
    sendDataCallback = callback;
}

/// @brief 获取重新连接次数
/// @return 返回当前重新连接次数
uint16_t CTC_Master_GetReConnectTimes(void)
{
    return reconnectTimes;
}

/// @brief 获取总接收字节数
/// @return 返回总接收字节数
uint32_t CTC_Master_GetTotalReceivedBytes(void)
{
    return totalReceivedBytes;
}

/// @brief 获取总发送字节数
/// @return 返回总发送字节数
uint32_t CTC_Master_GetTotalSentBytes(void)
{
    return totalSentBytes;
}

/// @brief 获取总接收正确消息数
/// @return 返回总接收正确消息数
uint32_t CTC_Master_GetTotalReceivedMsgCount(void)
{
    return totalReceivedMsgCount;
}

/// @brief 获取总发送正确消息数
/// @return 返回总发送正确消息数
uint32_t CTC_Master_GetTotalSentMsgCount(void)
{
    return totalSentMsgCount;
}

/// @brief 获取总接收错误消息数
/// @return 返回总接收错误消息数
uint32_t CTC_Master_GetTotalReceivedErrorMsgCount(void)
{
    return totalReceivedErrorMsgCount;
}

/// @brief 获取当前连接的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
/// @return 0=已连接并且获取到了设备ID,其他值表示未连接或未获取到设备ID
uint8_t CTC_Master_GetSlaveDeviceId(uint8_t *deviceId)
{
    if (deviceId) {
        memcpy(deviceId, slaveDeviceId, 16);
        return 0; // 已连接并获取到设备ID
    }
    return 1; // 未连接或未获取到设备ID
}

/// @brief 设置Master端的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
void CTC_Master_SetDeviceId(const uint8_t *deviceId)
{
    if (deviceId) {
        memcpy(masterDeviceId, deviceId, 16);
    }
}

/// @brief 获取发送缓冲区数据长度
/// @return 返回发送缓冲区数据长度
uint16_t CTC_Master_GetSendBufferDataLength(void)
{
    return CTCBuffer_DataLength(&sendBuffer);
}

/// @brief 获取发送缓冲区空闲长度
/// @return 返回发送缓冲区空闲长度
uint16_t CTC_Master_GetSendBufferFreeLength(void)
{
    return CTCBuffer_FreeLength(&sendBuffer);
}

/// @brief 获取接收缓冲区数据长度
/// @return 返回接收缓冲区数据长度
uint16_t CTC_Master_GetReceiveBufferDataLength(void)
{
    return CTCBuffer_DataLength(&receiveBuffer);
}

/// @brief 获取接收缓冲区空闲长度
/// @return 返回接收缓冲区空闲长度
uint16_t CTC_Master_GetReceiveBufferFreeLength(void)
{
    return CTCBuffer_FreeLength(&receiveBuffer);
}

/// @brief 获取连接状态
/// @return 返回当前连接状态,参考CTC_ClientConnState
CTC_ClientConnState CTC_Master_GetConnectState(void)
{
    return connState;
}

/// @brief 设置数据发送结果回调函数
/// @param callback 回调函数指针
void CTC_Master_SetDataSendResultCallback(CTC_MsgSendCallback callback)
{
    datasendresultCallback = callback;
}

/// @brief 获取Slave设备是否可消费
/// @return 1=不可消费,0=可消费,如果未握手或未连接则返回1
uint8_t CTC_Master_IsSlaveConsumable(void)
{
    if (connState != CTC_CLIENT_CONNSTATE_CONNECTED) {
        return 1; // 未连接或未握手
    }
    return slaveconsumable;
}

/// @brief 获取Slave端支持的CTC协议版本
/// @return 返回Slave端支持的CTC协议版本,如果未握手或未连接则返回0
uint16_t CTC_Master_GetSlaveCTCVersion(void)
{
    return slaveCTCversion;
}

/// @brief 打印过程的统计数据
void CTC_Master_PrintStatistics(void)
{
    DEBUG_INFO("CTC Master Statistics:\r\n");
    DEBUG_INFO("  Total Sent Bytes: %d\r\n", totalSentBytes);
    DEBUG_INFO("  Total Sent Messages: %d\r\n", totalSentMsgCount);
    DEBUG_INFO("  Total Resent Messages: %d\r\n", totalresendMsgCount);
    DEBUG_INFO("  Send Buffer Data Length: %d\r\n", CTCBuffer_DataLength(&sendBuffer));
    DEBUG_INFO("  Send Buffer Free Length: %d\r\n", CTCBuffer_FreeLength(&sendBuffer));
    DEBUG_INFO("  Total Received Bytes: %d\r\n", totalReceivedBytes);
    DEBUG_INFO("  Total Received Messages: %d\r\n", totalReceivedMsgCount);
    DEBUG_INFO("  Total Received Error Messages: %d\r\n", totalReceivedErrorMsgCount);
    DEBUG_INFO("  Receive Buffer Data Length: %d\r\n", CTCBuffer_DataLength(&receiveBuffer));
    DEBUG_INFO("  Receive Buffer Free Length: %d\r\n", CTCBuffer_FreeLength(&receiveBuffer));
}

// 抄表业务指令的处理----------------------------------------------------------------

/// @brief 发送抄表指令
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendReadMeterCommand(void)
{
    uint32_t nexttransactionid = CTC_Master_GetNextSendTransactionId();
    CTC_BufferResult res       = CTCBuffer_WriteMsgToSendBuffer(&sendBuffer, CTC_DEFAULT_PORTID, CTC_CMD_METER_READ, nexttransactionid, NULL, 0);
    if (res != CTC_BUFFER_SUCCESS) {
        DEBUG_WARN("CTC Master ReadMeter Write To Send Buffer Failed:%d\r\n", res);
        return 0;
    }
    return nexttransactionid;
}

/// @brief 设置抄表结果回调函数,如果从设备有多个参数一起返回,会多次调用此回调函数
/// @param callback 回调函数指针
void CTC_Master_SetReadMeterCallback(CTC_Master_ReadMeterCallback callback)
{
    readMeterCallback = callback;
}

/// 投币业务指令的处理----------------------------------------------------------------

/// @brief 发送投币指令
/// @note 投币指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 如果对方有回应会在CTC_Master_SetCoinInCallback设置的回调函数中返回投币结果
/// @param msg 指向投币消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendCoinInCommand(const CTC_CoinInMsgV1 *msg)
{
    uint8_t data[CTC_CMDLEN_COIN_IN];
    CTCBuffer_Uint32ToBytes(msg->CoinCount, &data[0]);
    memcpy(&data[4], msg->MemberId, 16);
    memcpy(&data[20], msg->RecordId, 16);
    return CTC_Master_SendMsgCommand(CTC_CMD_COIN_IN, data, CTC_CMDLEN_COIN_IN);
}

/// @brief 设置投币结果回调函数
/// @param callback 投币结果回调函数指针
void CTC_Master_SetCoinInRspCallback(CTC_Master_CoinInCallback callback)
{
    coinInCallback = callback;
}

// 通道选择业务指令的处理----------------------------------------------------------------

/// @brief 发送通道选择指令
/// @note 此指令没有专门的应答,指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @param msg 指向通道选择消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendSelectChannelCommand(const CTC_ChannelSelMsgV1 *msg)
{
    uint8_t data[CTC_CMDLEN_CHANNEL_SEL];
    data[0] = msg->Ticket;
    data[1] = msg->BlueTicket;
    return CTC_Master_SendMsgCommand(CTC_CMD_CHANNEL_SEL, data, CTC_CMDLEN_CHANNEL_SEL);
}

// 查询与设置单价业务指令的处理----------------------------------------------------------------

/// @brief 发送查询单价指令
/// @note 指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 如果对方有回应会在CTC_Master_SetQueryCoinPriceCallback设置的回调函数中返回查询结果
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendQueryCoinPriceCommand(void)
{
    return CTC_Master_SendMsgCommand(CTC_CMD_QUERY_COIN, NULL, 0);
}

/// @brief 设置查询单价结果回调函数
/// @param callback 查询单价结果回调函数指针
void CTC_Master_SetQueryCoinPriceCallback(CTC_Master_QueryCoinPriceCallback callback)
{
    queryCoinPriceCallback = callback;
}

/// @brief 发送设置单价指令
/// @note 指令发送结果会在CTC_Master_SetDataSendResultCallback设置的回调函数中返回
/// @note 此指令没有专门的应答
/// @param msg 指向设置单价消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Master_SendSetCoinPriceCommand(const CTC_CoinPriceMsgV1 *msg)
{
    uint8_t data[CTC_CMDLEN_QUERY_COIN];
    CTCBuffer_Uint16ToBytes(msg->CoinPerGame, &data[0]);
    return CTC_Master_SendMsgCommand(CTC_CMD_SET_COIN, data, CTC_CMDLEN_QUERY_COIN);
}

// 氛围灯业务指令的处理----------------------------------------------------------------
/// @brief 设置氛围事件回调函数
/// @param callback 回调函数指针
void CTC_Master_SetAtmosphereEventCallback(CTC_Master_AtmosphereEventCallback callback)
{
    atmosphereEventCallback = callback;
}

// 游戏奖励事件回调----------------------------------------------------------------
/// @brief 设置游戏奖励事件回调函数
/// @param callback 回调函数指针
void CTC_Master_SetGameRewardEventCallback(CTC_Master_GameRewardEventCallback callback)
{
    rewardEventCallback = callback;
}

// 实物奖励业务指令的处理----------------------------------------------------------------
/// @brief 设置实物奖励回调函数
/// @param callback 回调函数指针
void CTC_Master_SetPhysicalRewardCallback(CTC_Master_PhysicalRewardCallback callback)
{
    physicalRewardCallback = callback;
}
